package com.harvest.scientific.ladder.net

import BaseResponse
import com.google.gson.*

private val gson = Gson()

fun <T> JsonObject.toRespObj(clazz: Class<T>): BaseResponse<T?> {
    val code = this.get("furnishedLetterConnection")?.beInt()
    return BaseResponse(
        furnishedLetterConnection = code,
        upsetTroublesomeSaturdaySecondExpense = this.get("upsetTroublesomeSaturdaySecondExpense")?.beString(),
        firmSailingPublicHers = if (code == 1000) {
            getObjData(this,clazz)
        }else{
            kotlin.runCatching { getObjData(this,clazz) }.getOrNull()
        }
    )
}

private fun <T> getObjData(obj: JsonObject, clazz: Class<T>): T? {
    val dataObj = obj.get("firmSailingPublicHers")
    val data: T? = if (dataObj == null || dataObj.isJsonNull) {
        null
    } else if ((clazz.name == Any::class.java.name)) {
        (dataObj as T?)
    } else when (clazz) {
        String::class.java -> dataObj.asString as T?
        Int::class.java -> dataObj.asInt as T?
        Long::class.java -> dataObj.asLong as T?
        Double::class.java -> dataObj.asDouble as T?
        Boolean::class.java -> dataObj.asBoolean as T?
        Float::class.java -> dataObj.asFloat as T?
        else -> gson.fromJson(dataObj, clazz)
    }
    return data
}

fun <T> JsonObject.toRespArray(key: String, clazz: Class<T>): BaseResponse<List<T>> {
    return this.getAsJsonObject(key).toRespArray(clazz)
}

fun <T> JsonObject.toRespArray(clazz: Class<T>): BaseResponse<List<T>> {
    val code = this.get("furnishedLetterConnection")?.beInt()
    return BaseResponse(
        furnishedLetterConnection = code,
        upsetTroublesomeSaturdaySecondExpense = this.get("upsetTroublesomeSaturdaySecondExpense")?.beString(),
        firmSailingPublicHers = if (code==0){//成功但Json解析失败,是后台返回的数据有问题，不能依然走成功，让它在请求框架中捕获json异常错误返回
            getArrayData(this,clazz)
        }else{//返回非成功，data允许它Json解析失败，在这捕获后返回后端的错误码
            kotlin.runCatching { getArrayData(this,clazz) }.getOrNull()
        }
    )
}

private fun <T> getArrayData(obj: JsonObject, clazz: Class<T>): List<T> {
    var array = obj.get("firmSailingPublicHers")
    val data: List<T> = if (array == null || array.isJsonNull) {
        mutableListOf()
    } else {
        array = array.asJsonArray
        if (clazz.name == Any::class.java.name) {
            array.map { it as T }
        } else when (clazz) {
            String::class.java -> array.map { it.asString as T }
            Int::class.java -> array.map { it.asInt as T }
            Long::class.java -> array.map { it.asLong as T }
            Double::class.java -> array.map { it.asDouble as T }
            Boolean::class.java -> array.map { it.asBoolean as T }
            Float::class.java -> array.map { it.asFloat as T }
            else -> array.map { gson.fromJson(it, clazz) }
        }
    }
    return data
}

fun JsonElement.beJsonObject(defaultValue:JsonObject? = null): JsonObject?{
    if (this.isJsonObject){
        return this.asJsonObject
    }
    return defaultValue
}

fun JsonElement.beJsonArray(defaultValue:JsonArray? = null): JsonArray?{
    if (this.isJsonArray){
        return this.asJsonArray
    }
    return defaultValue
}

fun JsonElement.beBoolean(defaultValue:Boolean? = null):Boolean?{
    return if (this.isJsonNull) {
        defaultValue
    } else this.asBoolean
}

fun JsonElement.beString(defaultValue:String? = null):String?{
    return if (this.isJsonNull) {
        defaultValue
    } else asString
}

fun JsonElement.beShort(defaultValue:Short? = null):Short?{
    return if (this.isJsonNull) {
        defaultValue
    } else this.asShort
}

fun JsonElement.beInt(defaultValue:Int? = null):Int?{
    return if (this.isJsonNull) {
        defaultValue
    } else this.asInt
}

fun JsonElement.beLong(defaultValue:Long? = null):Long?{
    return if (this.isJsonNull) {
        defaultValue
    } else this.asLong
}

fun JsonElement.beFloat(defaultValue:Float? = null):Float?{
    return if (this.isJsonNull) {
        defaultValue
    } else this.asFloat
}

fun JsonElement.beDouble(defaultValue:Double? = null):Double?{
    return if (this.isJsonNull) {
        defaultValue
    } else this.asDouble
}

fun <T> JsonElement.parseObj(clazz: Class<T>): T {
    return gson.fromJson(this, clazz)
}

fun <T> JsonElement.parseArray(clazz: Class<T>): List<T>? {
    if (this.isJsonArray){
        return this.asJsonArray.mapNotNull {
            it.parseObj(clazz)
        }
    }
    return null
}

fun <T> JsonElement.tryParseObj(clazz: Class<T>): T? {
    return kotlin.runCatching {
        gson.fromJson(this,clazz)
    }.onFailure {
    }.getOrNull()
}

fun <T> JsonElement.tryParseArray(clazz: Class<T>, ignoreSingleErr:Boolean = false): List<T>? {
    if (this.isJsonArray){
        if (ignoreSingleErr){
            return kotlin.runCatching {
                this.asJsonArray.mapNotNull {
                    it.tryParseObj(clazz)
                }
            }.onFailure {
            }.getOrNull()
        }else{
            return kotlin.runCatching {
                this.asJsonArray.mapNotNull {
                    it.parseObj(clazz)
                }
            }.onFailure {
            }.getOrNull()
        }
    }
    return null
}

fun JsonObject?.getBoolean(memberName:String,defaultValue:Boolean? = null):Boolean?{
    return this?.get(memberName)?.beBoolean(defaultValue)
}

fun JsonObject?.getString(memberName:String,defaultValue:String? = null):String?{
    return this?.get(memberName)?.beString(defaultValue)
}

fun JsonObject?.getShort(memberName:String,defaultValue:Short? = null):Short?{
    return this?.get(memberName)?.beShort(defaultValue)
}

fun JsonObject?.getInt(memberName:String,defaultValue:Int? = null):Int?{
    return this?.get(memberName)?.beInt(defaultValue)
}

fun JsonObject?.getLong(memberName:String,defaultValue:Long? = null):Long?{
    return this?.get(memberName)?.beLong(defaultValue)
}

fun JsonObject?.getFloat(memberName:String,defaultValue:Float? = null):Float?{
    return this?.get(memberName)?.beFloat(defaultValue)
}

fun JsonObject?.getDouble(memberName:String,defaultValue:Double? = null):Double?{
    return this?.get(memberName)?.beDouble(defaultValue)
}

fun JsonObject?.getJsonArray(memberName:String,defaultValue:JsonArray? = null):JsonArray?{
    return this?.get(memberName)?.beJsonArray(defaultValue)
}

fun JsonObject?.getJsonObject(memberName:String,defaultValue:JsonObject? = null):JsonObject?{
    return this?.get(memberName)?.beJsonObject(defaultValue)
}


fun String?.beJsonObject(): JsonObject? {
    if (this.isNullOrEmpty()){
        return null
    }
    return kotlin.runCatching {
        JsonParser.parseString(this)?.beJsonObject()
    }.onFailure {
    }.getOrNull()
}
fun String?.beJsonArray(): JsonArray? {
    if (this.isNullOrEmpty()){
        return null
    }
    return kotlin.runCatching {
        JsonParser.parseString(this)?.beJsonArray()
    }.onFailure {
    }.getOrNull()
}

fun <T> String?.tryParseArray(block:(JsonObject)->T?):List<T>?{
    if (this.isNullOrEmpty()){
        return null
    }
    return kotlin.runCatching {
        JsonParser.parseString(this)?.beJsonArray()?.mapNotNull{
            it.beJsonObject()?.let(block)
        }
    }.onFailure {
    }.getOrNull()
}

fun <T> String.parseObj(clazz: Class<T>): T {
    return gson.fromJson(this, clazz)
}

fun <T> String.parseArray(clazz: Class<T>):List<T>?{
    return this.beJsonArray()?.parseArray(clazz)
}

fun <T> String.tryParseObj(clazz: Class<T>): T? {
    return kotlin.runCatching {
        if (this.isBlank()){
            null
        }else{
            gson.fromJson(this, clazz)
        }
    }.onFailure {
    }.getOrNull()
}

fun <T> String.tryParseArray(clazz: Class<T>, ignoreSingleErr:Boolean = false):List<T>?{
    return kotlin.runCatching {
        this.beJsonArray()?.tryParseArray(clazz,ignoreSingleErr)
    }.onFailure {
    }.getOrNull()
}

fun <T> JsonArray?.tryParseArray(block:(JsonObject)->T?):List<T>?{
    return kotlin.runCatching {
        this?.mapNotNull{
            it.beJsonObject()?.let(block)
        }
    }.onFailure {
    }.getOrNull()
}